package kotlinx.coroutines.script

import android.accessibilityservice.GestureDescription.StrokeDescription
import android.graphics.Path
import android.graphics.RectF
import android.os.Build
import androidx.annotation.RequiresApi
import kotlinx.coroutines.script.tes.phoneScreenWidth
import kotlinx.coroutines.script.tes.pt
import kotlinx.coroutines.script.tes.shake
import kotlinx.coroutines.delay
import kotlinx.coroutines.script.tes.Accessibility
import kotlinx.coroutines.script.tes.analysisEvent
import kotlinx.coroutines.script.tes.phoneScreenHeight
import kotlinx.coroutines.script.tes.randomFloat
import kotlin.math.cos
import kotlin.math.max
import kotlin.math.min
import kotlin.math.sin

object CaptureInit {
    // 激流入口修正
    suspend fun tryFix( selfHp: Block) {
            val rocker by lazy {
                val left = selfHp.left + ((phoneScreenWidth - selfHp.left * 2) * 0.16f).toInt()
                Block(C.V_ROCKER, left, 750.pt, 80.pt, 80.pt)
            }
            suspend fun rockerByAngleInit(name: String, angleList: List<Int>, dur: Long, widgetClickInterval: Long = 0) {
                val list = mutableListOf<Pair<Int, Int>>()
                list.add(Pair(rocker.x.shake(3), rocker.y.shake(3)))
                list.addAll(angleList.map {
                    GestureCenter.angleToPoint(
                        rocker,
                        it,
                        125.pt.shake(3.pt)
                    )
                })
                GestureCenter.playGestures(
                    listOf(XGesturePoint.stroke(name, list, dur)),
                    widgetClickInterval
                )
            }
            rockerByAngleInit("小地图人物中心修正1", listOf(270.shake(3)), 287L.shake(30))
            delay(2000)
    }
}

object GestureCenter {
    private val protectInterval get() = 62L.shake(22) // 130L.shake(22) //62L.shake(22)  // MuMu点击间隔一般120ms // 211L.shake(9)

    suspend fun playGestures(pointList: List<XGesturePoint>, widgetClickInterval: Long = 0) {
        Accessibility.playGestures(pointList)
        val force = widgetClickInterval < 0
        val wi = if (force) widgetClickInterval * -1 else widgetClickInterval
        val interval = protectInterval

        if (force) delay(wi)
        else delay(if (wi > interval) wi else interval)
    }

    fun angleToPoint(origin: Block, angle: Int, length: Int): Pair<Int, Int> {
        val a = ((angle % 360) + 360) % 360
        val part = when (a % 360) {
            in 0..89 -> 0
            in 90 .. 179 -> 1
            in 180 .. 269 -> 2
            in 270 .. 359 -> 3
            else -> 0
        }
        val h = Math.PI / 180 * (a % 90)
        val x = when (part) {
            0, 2 -> (sin(h) * length).toInt()
            else -> (cos(h) * length).toInt()
        }
        val y = when(part) {
            1, 3 -> (sin(h) * length).toInt()
            else -> (cos(h) * length).toInt()
        }
        val pointX = if (part == 0 || part == 1) x else -x
        val pointY = if (part == 1 || part == 2) y else -y
        return Pair(max(0, min(phoneScreenWidth - 1, origin.x + pointX)),
            max(0, min(phoneScreenHeight - 1, origin.y + pointY)))
    }
}

data class XGesturePoint(
    val name: String,
    val type: Int, // 0#click ; 1#longClick ; 2#swipe ; 3#angle  4#stroke
    val points: List<Pair<Int, Int>>,
    private val time: Long,
    val startDelay: Long,
) {
    val invokingTime = max(100, time) // 有time = 0的数据

    var propertiesError = false
    init {
        if (invokingTime <= 0L) {
            // analysisPostError(GesturePointV3Exception("GesturePoint [$name] error invokingTime = $invokingTime"))
            analysisEvent("G3_Point_${name}_error_time_${invokingTime}")
            propertiesError = true
        }
        val bounds = RectF()
        path.computeBounds(bounds, false /* unused */)
        if (bounds.bottom < 0 || bounds.top < 0 || bounds.right < 0 || bounds.left < 0) {
            // analysisPostError(GesturePointV3Exception("GesturePoint [$name] error 1 path $bounds"))
            analysisEvent("G3_Point_${name}_error_1_path_${bounds}")
            propertiesError = true
        } else if (bounds.bottom > phoneScreenHeight || bounds.top > phoneScreenHeight ||
            bounds.right > phoneScreenWidth || bounds.left > phoneScreenWidth
        ) {
            // analysisPostError(GesturePointV3Exception("GesturePoint [$name] error 2 path $bounds"))
            analysisEvent("G3_Point_${name}_error_2_path_${bounds}")
            propertiesError = true
        }
    }

    private val path: Path get() = pointsToPath(points)
    @RequiresApi(Build.VERSION_CODES.O)
    fun strokeDescription(willContinue: Boolean = false): StrokeDescription {
        return StrokeDescription(path, startDelay, max(60, invokingTime), willContinue)
    }

    override fun toString(): String {
        return "[${name}${ if (startDelay>0) "#延迟:$startDelay" else "" } #时长:$invokingTime]"
    }

    companion object {
        fun stroke(name: String, points: List<Pair<Int, Int>>, invokingTime: Long): XGesturePoint {
            return XGesturePoint(name = name, type = 4, points = points, time = invokingTime, startDelay = 0)
        }

        private fun pointsToPath(points: List<Pair<Int, Int>>): Path {
            val path = Path()
            if (points.isEmpty()) return path

            if (points.size == 2 && points[0].first == points[1].first && points[0].second == points[1].second) {
                // click
                val x = points[0].first.randomFloat
                val y = points[0].second.randomFloat
                path.moveTo(x, y)
                path.lineTo(x, y)
            } else {
                path.moveTo(points[0].first.randomFloat, points[0].second.randomFloat)
                for (i in 1 until points.size) {
                    path.lineTo(
                        points[i].first.randomFloat,
                        points[i].second.randomFloat
                    )
                }
            }

            return path
        }
    }
}